package good_src.Strategy;

import java.util.Collection;
import good_src.Interfaces.*;

/**
 * 
 * @author Tangi Midy & Fabien Le Peih
 * <p>The atomic principle consists in setting the same value to every
 * requester knowing and considering possible the loss of value</p>
 * <p> The prime objective is "The same value for all the requesters"</p>
 * 
 */
public class Atomique implements Algorithme, Runnable {

	private Capteur<Integer> subject; // The initial capteur
	private Collection<ObservateurCapteur> canaux; //The collection of streams
	private VerifCanaux verifCanaux; // The intern Thread class
	private Thread t;
	int valuetoUpdate;

	/**
	 * 
	 * @param subject the referenced subject
	 */
	public Atomique(Capteur<Integer> subject) {
		this.subject = subject;
		canaux = subject.getObservers();

		verifCanaux = new VerifCanaux(canaux);
	}

	/**
	 * 
	 * @see good_src.Interfaces.Algorithme#configure()
	 */
	@Override
	
	public void configure() {
		valuetoUpdate = subject.getValue();
	}

	/**
	 * 
	 * @see good_src.Interfaces.Algorithme#execute()
	 */
	@Override
	public void execute() {
		t = new Thread(verifCanaux, "Thread" + subject.getValue());
		t.start();
		if (verifCanaux.isUpdated()) {
			verifCanaux.setUpdated(false);
		}
	}
	
	/**
	 * 
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {
		//The execution is possible only if every requester has been updated
		if (verifCanaux.isUpdatable()) {
			verifCanaux.updatable = false;
			//We block the other threads while updating
			verifCanaux.setValue(subject.getValue());
			execute();
		}
	}

	/**
	 * 
	 * @return the atomic Value
	 */
	public int getValue() {
		return verifCanaux.getValue();
	}

	/**
	 * 
	 * @author Tangi Midy & Fabien Le Peih
	 * Intern class thats saves the strategy value
	 * and updates the streams
	 */
	private class VerifCanaux implements Runnable {

		private int value;//The value passed to the requesters
		private Collection<ObservateurCapteur> canaux;
		private boolean updated = false, updatable = true;

		public VerifCanaux(Collection<ObservateurCapteur> canaux) {
			this.canaux = canaux;
		}

		/**
		 * 
		 * @see java.lang.Runnable#run()
		 */
		@Override
		public void run() {
			for (ObservateurCapteur c : canaux) {
				c.update();
			}
			updated = true;
			updatable = true;
		}

		public void setValue(int value) {
			this.value = value;
		}

		public int getValue() {
			return value;
		}

		public boolean isUpdated() {
			return updated;
		}

		public void setUpdated(boolean updated) {
			this.updated = updated;
		}

		public boolean isUpdatable() {
			return updatable;
		}

	}



}
